<?php

namespace slinks\core\dependencyInjectionExt;

use slinks\core\DependencyInjection\ContainerBuilder;
use slinks\core\DependencyInjection\Loader\XmlFileLoader;
use slinks\core\dependencyInjectionExt\ContainerUtil;
use slinks\core\dependencyInjectionExt\ContainerConstants;
use slinks\core\Config\Loader\DelegatingLoader;
use slinks\core\DependencyInjection\Loader\YamlFileLoader;
use slinks\core\DependencyInjection\Loader\IniFileLoader;
use slinks\core\DependencyInjection\Loader\PhpFileLoader;
use slinks\core\Config\Loader\LoaderResolver;
use slinks\core\Config\FileLocator;


/**
 * Responsible for actually creating applications/plugins based upon any files found.
 *
 * @author navid
 */
class ApplicationFileVisitor implements \slinks\common\io\IFileSystemVisitor {

    private $container;
    private $fileSuffix;
    private $autoRegisterNamespace;
    

    public function __construct(ContainerBuilder $container,$fileSuffix,$autoRegisterNamespace) {
        $this->container = $container;
        $this->fileSuffix = $fileSuffix;
        $this->autoRegisterNamespace = $autoRegisterNamespace;
    }

    /**
     * This is called for evey object accessed during the traversal of the fielsystem by the FileSystemReader.
     * @param SplFileInfo $info the SPLFileInfo object to represent the current portion of the file/directory tree.
     */
    public function visit(\SplFileInfo $info) { 
        
        // found a application definition file.
        $applicationName = str_replace($this->fileSuffix, '', $info->getFilename());
        
        if($this->autoRegisterNamespace){
            // add namespace to parameters 
            $namespace = $info->getPathInfo()->getFilename();
            $path = $info->getPathInfo()->getPathInfo()->getRealPath();
            
            ContainerUtil::addValueToArrayParameter($this->container, 
                                                    ContainerConstants::PARAM_AUTO_NAMESPACES, 
                                                    array($namespace,$path));
            
            $loader = new \slinks\common\UniversalClassLoader();
            // namespace must always be parent directory
            $loader->registerNamespace($namespace,$path);
            $loader->register();
        }
        
        // add parameter for root directory.
        $this->container->setParameter($applicationName.ContainerConstants::APPLICATION_DIR_PARAM_SUFFIX,
                                       $info->getPathInfo()->getRealPath());
        
        // add applications to the list of applications
        // add root application info if this is the first application
        if(!$this->container->hasParameter(ContainerConstants::PARAM_ROOT_APPLICATION)){
            $this->container->setParameter(ContainerConstants::PARAM_ROOT_APPLICATION,$applicationName);
        }
        
        ContainerUtil::addValueToArrayParameter($this->container, ContainerConstants::PARAM_APPLICATIONS, $applicationName);
        
        // first try to register any extensions and or compilers then load the config.
        $dir = $info->getPath().'/extensions';
        if(is_dir($dir)){
            ContainerUtil::addExtensions($this->container, $dir);
        }
        
        $loader = $this->getLoader($this->container,$info->getPath());
        $loader->load($info->getFilename());      
    }

        /**
     *
     * @param ContainerInterface $container
     * @return Loader
     */
    protected function getLoader(ContainerBuilder $container,$path) {
        $fileLocator = new FileLocator($path);
        $resolver = new LoaderResolver(array(
                    new XmlFileLoader($container,$fileLocator),
                    new YamlFileLoader($container,$fileLocator),
                    new IniFileLoader($container,$fileLocator),
                    new PhpFileLoader($container,$fileLocator)
                ));
        return new DelegatingLoader($resolver);
    }
    
}

